package yartiss.engine.simulation.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Scanner;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * 
 * @author Manar Qamhieh
 * 
 */
public class XmlFromFileWriter {

	private Document document;
	private Element mainElmt;
	private final OutputStream out;
	private final Scanner scanner;

	public XmlFromFileWriter(String srcFile, String destFile) throws Exception {
		this(new FileInputStream(srcFile), new FileOutputStream(destFile));
	}

	public XmlFromFileWriter(File srcFile, File destFile) throws Exception {
		this(new FileInputStream(srcFile), new FileOutputStream(destFile));
	}

	public XmlFromFileWriter(InputStream in, OutputStream out) throws Exception {
		this.out = out;
		scanner = new Scanner(in);
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		builder = factory.newDocumentBuilder();
		document = builder.newDocument();
		mainElmt = document.createElement("dataset");
		document.appendChild(mainElmt);
		parseSrcData();
		close();
	}

	private void parseSrcData() {
		String line = scanner.nextLine();
		String[] tokens = line.split(" ");
		Element policyElmt = document.createElement("policy");
		policyElmt.setAttribute("name", tokens[0]);
		policyElmt
				.setAttribute("nbParams", Integer.toString(tokens.length - 1));
		if (tokens.length > 1) {
			Element paramElmt;
			for (int i = 1; i < tokens.length; i++) {
				paramElmt = document.createElement("parameter");
				paramElmt.setAttribute("name", "");
				paramElmt.setAttribute("value", tokens[i]);
				policyElmt.appendChild(paramElmt);
			}

		}
		mainElmt.appendChild(policyElmt);

		tokens = scanner.nextLine().split(" ");
		Element simElmt = document.createElement("simulation");
		simElmt.setAttribute("endValue", tokens[0]);

		int nbProc = (tokens.length > 1) ? Integer.parseInt(tokens[1]) : 1;
		simElmt.setAttribute("nbProc", Integer.toString(nbProc));
		mainElmt.appendChild(simElmt);

		Element energyElmt = document.createElement("energyProfile");

		String[] energyProfileLine = scanner.nextLine().split(" ");
		if (energyProfileLine.length < 3)
			throw new IllegalArgumentException(
					"Energy profile parameters are incomplete! it should be minimum (pr, Emax, Emin)");
		energyElmt.setAttribute("pr", energyProfileLine[0]);
		energyElmt.setAttribute("Emax", energyProfileLine[1]);
		energyElmt.setAttribute("Emin", energyProfileLine[2]);
		if(energyProfileLine.length > 3)
			energyElmt.setAttribute("E0", energyProfileLine[3]);

		mainElmt.appendChild(energyElmt);

		Element tasksElmt = document.createElement("tasks");
		int nbTasks = Integer.parseInt(scanner.nextLine().trim());
		tasksElmt.setAttribute("nbTasks", Integer.toString(nbTasks));
		tasksElmt.setAttribute("type", "simple");

		Element taskElmt;
		for (int i = 0; i < nbTasks; i++) {
			tokens = scanner.nextLine().split(" ");
			if (tokens.length < 6)
				throw new IllegalArgumentException(
						"Task parameters are incomplete (firstRelease, wcet, wcee, period, deadline, priority)");
			taskElmt = document.createElement("task");
			taskElmt.setAttribute("type", "simple");
			taskElmt.setAttribute("firstRelease", tokens[0]);
			taskElmt.setAttribute("wcet", tokens[1]);
			taskElmt.setAttribute("wcee", tokens[2]);
			taskElmt.setAttribute("period", tokens[3]);
			taskElmt.setAttribute("deadline", tokens[4]);
			taskElmt.setAttribute("priority", tokens[5]);
			tasksElmt.appendChild(taskElmt);
		}
		mainElmt.appendChild(tasksElmt);
		
	}

	/**
	 * Closes the stream opened by this TasksetWriter. If this method is not
	 * called, then the XML stream is never flushed (Nothing is written outside
	 * the memory).
	 */
	public void close() {
		TransformerFactory factory = TransformerFactory.newInstance();
		factory.setAttribute("indent-number", new Integer(2));
		Transformer transformer = null;
		try {
			transformer = factory.newTransformer();
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		}
		transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		DOMSource src = new DOMSource(document);
		try {
			StreamResult stream = new StreamResult(new OutputStreamWriter(
					out, "UTF-8"));

			transformer.transform(src, stream);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
